﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Player : Mob
{
    [Header("最大速度设置")]
    [SerializeField]
    private float _walkSpeed;
    [SerializeField]
    private float _runSpeed;
    [SerializeField]
    private float _sprintSpeed;
    [SerializeField]
    [Range(0f, 1f)]
    private float _fallingSpeed;

    private float currentSpeed;

    [SerializeField]
    private bool _doFalling;
    [SerializeField]
    private bool _doAttacking;
    private bool attack;
    private bool _doHurt;
    private float alertTimer;

    private bool doSprint;

    public float WalkSpeed { get { return _walkSpeed; } }
    public float RunSpeed { get { return _runSpeed; } }
    public float SprintSpeed { get { return _sprintSpeed; } }

    public bool DoFalling { get { return _doFalling; } }

    public bool DoAlert { get { return _doAttacking || _doHurt; } }

    // private Animator animator;
    private CharacterController characterController;

    private Vector3 movement;
    private Vector3 animatorMovement;
    private Vector3 towards;
    private float angle;

    [SerializeField]
    private string aniState;

    public bool FaceToAttacker;

    [SerializeField]
    private GameObject alertObject;

    override protected void Awake()
    {
        base.Awake();
        // animator = GetComponent<Animator>();
        characterController = GetComponent<CharacterController>();
        // GameManager.Instance.PlayerEnter(gameObject);
    }

    private void Start()
    {
        GameManager.Instance.PlayerEnter(gameObject);
    }

    private void OnDisable()
    {
        if (GameManager.IsCreated())
            GameManager.Instance.PlayerExit(gameObject);
    }

    private void Update()
    {
        GetInput();
        SetAnimate();
        GetAnimateState();
        Timer();
    }

    private void FixedUpdate()
    {
        if (aniState == "Move")
        {
            DetectFalling();
            SetTowards();

            characterController.Move(towards);
            transform.eulerAngles = new Vector3(transform.eulerAngles.x, angle, transform.eulerAngles.z);
        }
    }

    private void DetectFalling()
    {
        //TODO: 修改坠落判定
        Ray ray = new Ray(transform.position + Vector3.up * 0.1f, Vector3.down * 0.2f);
        _doFalling = !Physics.Raycast(ray, 0.2f);
    }

    private void GetAnimateState()
    {
        if (animator.GetBool("Dead"))
        {
            aniState = "Dead";
            return;
        }

        var state = animator.GetCurrentAnimatorStateInfo(0);
        if (state.IsName("Base Layer.Attack"))
        {
            aniState = "Attack";
        }
        else if (state.IsName("Base Layer.Hurt"))
        {
            aniState = "Hurt";
        }
        else
        {
            aniState = "Move";
        }
    }

    private void SetAnimate()
    {
        animator.SetBool("Falling", DoFalling);

        if (DoFalling)
        {
            animator.SetBool("Walk", false);
            return;
        }

        if (attack)
        {
            animator.SetTrigger("Attack");
            attack = false;
            return;
        }

        if (movement == Vector3.zero)
        {
            animator.SetBool("Walk", false);
            animator.SetBool("Run", false);
            animator.SetBool("Sprint", false);
        }
        else
        {
            if (!DoAlert)
            {
                animator.SetBool("Walk", false);
                animator.SetBool("Run", !doSprint);
                animator.SetBool("Sprint", doSprint);
                animator.SetInteger("Forward", 1);
                animator.SetInteger("Right", 0);
            }
            else
            {
                animator.SetBool("Walk", true);
                animator.SetBool("Run", false);
                animator.SetBool("Sprint", false);

                if (animatorMovement.z > 0.1f)
                {
                    animator.SetInteger("Forward", 1);
                }
                else if (animatorMovement.z < -0.1f)
                {
                    animator.SetInteger("Forward", -1);
                }
                else
                {
                    animator.SetInteger("Forward", 0);
                }

                if (animatorMovement.x > 0.3f)
                {
                    animator.SetInteger("Right", 1);
                }
                else if (animatorMovement.x < -0.3f)
                {
                    animator.SetInteger("Right", -1);
                }
                else
                {
                    animator.SetInteger("Right", 0);
                }
            }
        }
    }

    private void GetInput()
    {
        movement = InputManager.Instance.movement;

        if (InputManager.Instance.doSprintDown) { doSprint = true; }

        if (InputManager.Instance.doAttackDown) { attack = true; _doAttacking = true; alertTimer = 0f; doSprint = false; }

        if (InputManager.Instance.doSprintUp) { doSprint = false; }
    }

    private void Timer()
    {
        if (movement == Vector3.zero)
        {
            alertTimer = 0f;
        }
        else if (DoAlert)
        {
            alertTimer += Time.deltaTime;
            if (alertTimer >= 5f || doSprint) { _doAttacking = false; _doHurt = false; alertTimer = 0f; alertObject = null; }
        }
    }

    protected virtual void SetTowards()
    {
        if (aniState == "Move")
        {
            if (doSprint)
            {
                towards = movement * SprintSpeed * Time.fixedDeltaTime;
            }
            else if (!DoAlert)
            {
                towards = movement * RunSpeed * Time.fixedDeltaTime;
            }
            else
            {
                towards = movement * WalkSpeed * Time.fixedDeltaTime;
            }

            if (_doFalling) { towards = towards * _fallingSpeed; }
        }
        else
        {
            towards = Vector3.zero;
        }

        if (DoAlert)
        {
            if (!FaceToAttacker || alertObject == null)
            {
                //朝向鼠标方向
                var playerPoint = Camera.main.WorldToScreenPoint(transform.position);
                var point = Input.mousePosition - playerPoint;
                angle = Mathf.Atan2(point.x, point.y) * Mathf.Rad2Deg;

                animatorMovement = Quaternion.AngleAxis(-angle, Vector3.up) * movement;
            }
            else
            {
                //朝向攻击者方向
                var playerPoint = Camera.main.WorldToScreenPoint(transform.position);
                var attackPoint = Camera.main.WorldToScreenPoint(alertObject.transform.position);
                var point = attackPoint - playerPoint;
                angle = Mathf.Atan2(point.x, point.y) * Mathf.Rad2Deg;

                animatorMovement = Quaternion.AngleAxis(-angle, Vector3.up) * movement;
            }
        }
        else if (movement.magnitude > 0.2f)
        {
            //朝向移动方向
            angle = Mathf.Atan2(towards.x, towards.z) * Mathf.Rad2Deg;
        }
    }

    public override void TakeDamage(int damage, GameObject gObj)
    {
        base.TakeDamage(damage, gObj);
        alertTimer = 0f;
        _doHurt = true;

        alertObject = gObj;
    }

    //攻击判定
    [SerializeField]
    private List<Mob> attackTargets = new List<Mob>();

    private void OnTriggerEnter(Collider other)
    {
        var mob = other.gameObject.GetComponent<Mob>();
        if (mob != null && mob != this) { attackTargets.Add(mob); }
    }

    private void OnTriggerExit(Collider other)
    {
        var mob = other.GetComponent<Mob>();
        if (mob != null) { attackTargets.Remove(mob); }
    }

    public void Attack(int mul)
    {
        animator.SetBool("Move", true);
        foreach (var item in attackTargets)
        {
            item.TakeDamage(data.Damage * mul, gameObject);
        }
    }
}
